import {TypeCheck, Utils} from './common.js'

function _Subscribe(_map, type, cbFn) {
    let _arr = _map.get(type);
    if(!_arr) {
        _arr = [];
        _map.set(type, _arr);
    }
    const _idx = _arr.indexOf(cbFn);
    if(_idx < 0) {
        _arr.push(cbFn);
        return true;
    }
    return false;
}

export function EventDispatcher() {
    const _mapListener = new Map();
    return Object.freeze({
        Release: () => {
            _mapListener.clear();
            _mapListener = undefined;
        },

        Unsubscribe: (type, cbFn) => {
            const _arr = _mapListener.get(type);
            if(_arr) {
                let _i = _arr.indexOf(cbFn);
                if(_i >= 0) {
                    _arr.splice(_i, 1);
                    return true;
                }
            }
            return false;
        },

        // cbFn should bind to its caller;
        Subscribe: (type, cbFn) => {
            if(TypeCheck.IsArray(type)) {
                type.forEach((t) => {
                    _Subscribe(_mapListener, t, cbFn);
                });
                return true;
            } else {
                return _Subscribe(_mapListener, type, cbFn);
            }
        },

        Dispatch: (event) => {
            const _arr = _mapListener.get(event.type);
            if(_arr) {
                _arr.forEach((v) => {
                    v(event);
                });
                return true;
            }
            return false;
        },
    });
}

export class Module {
    constructor(dispatcher) {
        Utils.DefineFixedProperty(this, '_dispatcher', dispatcher ?? Object.freeze(EventDispatcher()));
    }
    Dispatch(event) {
        return this._dispatcher.Dispatch(event);
    }
    Subscribe(type, cbFn) {
        return this._dispatcher.Subscribe(type, cbFn);
    }
    Unsubscribe(type, cbFn) {
        return this._dispatcher.Unsubscribe(type, cbFn);
    }
}

